/**
 * @file		i2c.c
 * @brief		I2C
 * @note		None
 * @attention	None
 * 
 * <B><I>ALL RIGHTS RESERVED, COPYRIGHT&copy; SOCIONEXT INCORPORATED 2016</I></B>
 */

/* Standard includes. */
#include <stdio.h>

#include "dd_arm.h"

/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"

#include "dd_pmc_i2c.h"
#include "i2c.h"

#include "ipcu.h"

// Notification enable.
static volatile int iI2CSendNotificationEnable = 0;
static volatile int iI2CReceiveNotificationEnable = 0;

// Buffer data.
static volatile T_I2C_SEND_BUFFER xSendBuffer = { 0, 0, 0 };
static volatile T_I2C_RECEIVE_BUFFER xReceiveBuffer = { 0, 0, 0, 0, 0 };

// Local function.
static T_DD_PMC_I2C_ACTION prvI2CSendCallback(E_DD_PMC_I2C_RECV xRecvAction, UCHAR ucRecvData);
static T_DD_PMC_I2C_ACTION prvI2CReceiveCallback(E_DD_PMC_I2C_RECV xRecvAction, UCHAR ucRecvData);


/**
I2C Send callback function.
*/
static T_DD_PMC_I2C_ACTION prvI2CSendCallback(E_DD_PMC_I2C_RECV xRecvAction, UCHAR ucRecvData)
{
	T_DD_PMC_I2C_ACTION	xRetAction;
	BaseType_t			xHigherPriorityTaskWoken, xResult;
	unsigned long		ulData[3];
	
	// Stop.
	Dd_PMC_I2C_Stop_Master();
	Dd_PMC_I2C_Terminate();
	
	// Notification.
	if (iI2CSendNotificationEnable) {
		xHigherPriorityTaskWoken = pdFALSE;
		
		// Set I2C Send Notify data
		ulData[0] = 0x02000007;
		ulData[1] = 0;
		ulData[2] = 0;
		vIPCUSetNotifyCommand(ulData, 3);
		
		// Set Event Flag : I2C Send Notification.
		xResult = xEventGroupSetBitsFromISR(xNotifyEventFlag, (1 << NFY_I2C_SEND), &xHigherPriorityTaskWoken);
		if (xResult == pdPASS) {
			portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
		}
	}
	
	// Set Return value.
	xRetAction.action_mode	= 0;	// no action.
	xRetAction.send_data	= 0;	// no data.
	
	return xRetAction;
}

/**
I2C Receive callback function.
*/
static T_DD_PMC_I2C_ACTION prvI2CReceiveCallback(E_DD_PMC_I2C_RECV xRecvAction, UCHAR ucRecvData)
{
	T_DD_PMC_I2C_ACTION		xRetAction;
	T_DD_PMC_I2C_START_INFO	xStartInfo;
	BaseType_t				xHigherPriorityTaskWoken, xResult;
	unsigned long			ulData[3];
	
	// write pointer
	if (xReceiveBuffer.pointer != 0) {
		*((ULONG*)xReceiveBuffer.pointer) = xReceiveBuffer.address + (ucRecvData - 1);
	}
	
	// I2C Stop
	Dd_PMC_I2C_Stop_Master();
	Dd_PMC_I2C_Terminate();
	
	// Notification.
	if (iI2CReceiveNotificationEnable) {
		xHigherPriorityTaskWoken = pdFALSE;
		
		// Set I2C Receive Notify data
		ulData[0] = 0x02000008;
		ulData[1] = 0;
		ulData[2] = 0;
		vIPCUSetNotifyCommand(ulData, 3);
		
		// Set Event Flag : I2C Receive Notification.
		xResult = xEventGroupSetBitsFromISR(xNotifyEventFlag, (1 << NFY_I2C_RECEIVE), &xHigherPriorityTaskWoken);
		if (xResult == pdPASS) {
			portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
		}
	}
	
	switch (xReceiveBuffer.overlap) {
		case 1:		// 1:cyclic
			xStartInfo.rw_mode		= E_DD_PMC_I2C_RW_MODE_READ;
			xStartInfo.rw_data_len	= xReceiveBuffer.size;
			xStartInfo.rw_data		= (UCHAR*)xReceiveBuffer.address;
			Dd_PMC_I2C_Start_Master(&xStartInfo, (VP_PMC_I2C_CALLBACK)prvI2CReceiveCallback);
			break;
		case 2:		// 2:same position
			xStartInfo.rw_mode		= E_DD_PMC_I2C_RW_MODE_READ;
			xStartInfo.rw_data_len	= 1;
			xStartInfo.rw_data		= (UCHAR*)(xReceiveBuffer.address + xReceiveBuffer.size - 1);
			Dd_PMC_I2C_Start_Master(&xStartInfo, (VP_PMC_I2C_CALLBACK)prvI2CReceiveCallback);
			break;
		default:	// 0:no-overlap
			break;
	}
	
	// Set Return value.
	xRetAction.action_mode	= 0;	// no action.
	xRetAction.send_data	= 0;	// no data.
	
	return xRetAction;
}

/**
I2C Send start.
@retval  0 : success
@retval  1 : parameter error.
@retval  3 : function error.
*/
int iI2CSendStart(void)
{
	int							iRes = 0;
	T_DD_PMC_I2C_CTRL_MASTER	xCtrlMaster;
	T_DD_PMC_I2C_START_INFO		xStartInfo;
	
	if ((xSendBuffer.address == 0) || (xSendBuffer.size == 0) || (xSendBuffer.slave_address == 0)) {
		// parameter error.
		return 1;
	}
	
	xCtrlMaster.bps					= E_DD_PMC_I2C_BPS_400;
	xCtrlMaster.dest_slave_addr_len	= E_DD_PMC_I2C_ADDR_LEN_7;
	xCtrlMaster.dest_slave_addr		= xSendBuffer.slave_address;
	iRes = Dd_PMC_I2C_Ctrl_Master(&xCtrlMaster);
	if(iRes != D_DDIM_OK) {
		// function error.
		return 3;
	}
	
	xStartInfo.rw_mode		= E_DD_PMC_I2C_RW_MODE_WRITE;
	xStartInfo.rw_data_len	= xSendBuffer.size;
	xStartInfo.rw_data		= (UCHAR*)xSendBuffer.address;
	iRes = Dd_PMC_I2C_Start_Master(&xStartInfo, (VP_PMC_I2C_CALLBACK)prvI2CSendCallback);
	if(iRes != D_DDIM_OK) {
		// function error.
		return 3;
	}
	
	// normal end.
	return 0;
}

/**
I2C Receive start.
@retval  0 : success
@retval  1 : parameter error.
@retval  3 : function error.
*/
int iI2CReceiveStart(void)
{
	int							iRes = 0;
	T_DD_PMC_I2C_CTRL_MASTER	xCtrlMaster;
	T_DD_PMC_I2C_START_INFO		xStartInfo;
	
	if ((xReceiveBuffer.address == 0) || (xReceiveBuffer.size == 0) || (xReceiveBuffer.slave_address == 0)) {
		// parameter error.
		return 1;
	}
	
	xCtrlMaster.bps					= E_DD_PMC_I2C_BPS_400;
	xCtrlMaster.dest_slave_addr_len	= E_DD_PMC_I2C_ADDR_LEN_7;
	xCtrlMaster.dest_slave_addr		= xReceiveBuffer.slave_address;
	iRes = Dd_PMC_I2C_Ctrl_Master(&xCtrlMaster);
	if(iRes != D_DDIM_OK) {
		// function error.
		return 3;
	}
	
	xStartInfo.rw_mode		= E_DD_PMC_I2C_RW_MODE_READ;
	xStartInfo.rw_data_len	= xReceiveBuffer.size;
	xStartInfo.rw_data		= (UCHAR*)xReceiveBuffer.address;
	iRes = Dd_PMC_I2C_Start_Master(&xStartInfo, (VP_PMC_I2C_CALLBACK)prvI2CReceiveCallback);
	if(iRes != D_DDIM_OK) {
		// function error.
		return 3;
	}
	
	// normal end.
	return 0;
}

/**
I2C Receive stop.
@retval  0 : success
*/
int iI2CReceiveStop(void)
{
	Dd_PMC_I2C_Terminate();
	
	// normal end.
	return 0;
}

/**
set I2C Send notification.
@param [in]	enable		notification enable.<br>
						0:disable, 1:enable
@retval  0 : success
@retval  1 : parameter error
*/
int iI2CSendNotification(int enable)
{
	if ((enable != 0) && (enable != 1)) {
		// parameter error.
		return 1;
	}
	
	// Set notification.
	iI2CSendNotificationEnable = enable;
	
	// normal end.
	return 0;
}

/**
set I2C Receive notification.
@param [in]	enable		notification enable.<br>
						0:disable, 1:enable
@retval  0 : success
@retval  1 : parameter error
*/
int iI2CReceiveNotification(int enable)
{
	if ((enable != 0) && (enable != 1)) {
		// parameter error.
		return 1;
	}
	
	// Set notification.
	iI2CReceiveNotificationEnable = enable;
	
	// normal end.
	return 0;
}

/**
set I2C input buffer for send.
@param [in]	buff		Send buffer data.
@retval  0 : success
@retval  1 : parameter error
*/
int iI2CSetSendBuffer(T_I2C_SEND_BUFFER const* const buff)
{
	if (buff == 0) {
		// parameter error.
		return 1;
	}
	
	xSendBuffer = *buff;
	
	// normal end.
	return 0;
}

/**
set I2C input buffer for receive.
@param [in]	buff		Receive buffer data.
@retval  0 : success
@retval  1 : parameter error
*/
int iI2CSetReceiveBuffer(T_I2C_RECEIVE_BUFFER const* const buff)
{
	if (buff == 0) {
		// parameter error.
		return 1;
	}
	
	xReceiveBuffer = *buff;
	
	// normal end.
	return 0;
}

